import type {AxiosResponseHeaders} from 'axios';
import type {RequestClientOptions} from '../types';

import {
    authenticateResponseInterceptor,
    defaultResponseInterceptor,
    errorMessageResponseInterceptor,
} from '../interceptor/interceptor';

import {RequestClient} from './client';

import {useAppConfig} from '#/hooks';
import {useAccessStore, useAuthStore} from '#/stores';
import { cloneDeep } from '#/utils';

import {preferences} from '#/preferences';

import {message} from 'ant-design-vue';
import JSONBigInt from 'json-bigint';

import {refreshToken} from '../../core/auth';

const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);

function createRequestClient(baseURL: string, options?: RequestClientOptions) {
    const client = new RequestClient({
        ...options,
        baseURL,
        transformResponse: (data: any, header: AxiosResponseHeaders) => {
            // storeAsString指示将BigInt存储为字符串，设为false则会存储为内置的BigInt类型
            return header.getContentType()?.toString().includes('application/json')
                ? cloneDeep(
                    JSONBigInt({ storeAsString: true, strict: true }).parse(data),
                )
                : data;
        },
    });

    /**
     * 重新认证逻辑
     */
    async function doReAuthenticate() {
        console.warn('Access token or refresh token is invalid or expired. ');
        const accessStore = useAccessStore();
        const authStore = useAuthStore();
        accessStore.setAccessToken(null);
        if (
            preferences.app.loginExpiredMode === 'modal' &&
            accessStore.accessChecked
        ) {
            accessStore.setLoginExpired(true);
        } else {
            await authStore.authLogout();
        }
    }

    /**
     * 刷新token逻辑
     */
    async function doRefreshToken() {
        const accessStore = useAccessStore();
        const resp = await refreshToken();
        const newToken = resp.data;
        accessStore.setAccessToken(newToken);
        return newToken;
    }

    function formatToken(token: null | string) {
        return token ? `${token}` : null;
    }

    // 请求头处理
    client.addRequestInterceptor({
        fulfilled: async (config) => {
            const accessStore = useAccessStore();

            config.headers.Authorization = formatToken(accessStore.accessToken);
            config.headers['Accept-Language'] = preferences.app.locale;
            return config;
        },
    });

    // 处理返回的响应数据格式
    client.addResponseInterceptor(
        defaultResponseInterceptor({
            codeField: 'code',
            dataField: 'data',
            successCode: 200,
        }),
    );

    // token过期的处理
    client.addResponseInterceptor(
        authenticateResponseInterceptor({
            client,
            doReAuthenticate,
            doRefreshToken,
            enableRefreshToken: preferences.app.enableRefreshToken,
            formatToken,
        }),
    );

    // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里
    client.addResponseInterceptor(
        errorMessageResponseInterceptor((msg: string, error) => {
            // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg
            // 当前mock接口返回的错误字段是 error 或者 message
            const responseData = error?.response?.data ?? {};
            const errorMessage = responseData?.error ?? responseData?.message ?? '';
            // 如果没有错误信息，则会根据状态码进行提示
            message.error(errorMessage || msg);
        }),
    );

    return client;
}

export const requestClient = createRequestClient(apiURL, {
    responseReturn: 'data',
});